package com.groovy.demo;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import groovy.lang.GroovyClassLoader;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 动态脚本工厂
 * 作用：
 * 通过字符串源码生成Class
 * Class -> 实例
 *
 * @author donghaibin
 * @date 2019/11/19
 */
public class DynamicFactory {

    /**
     * 单例
     */
    private static DynamicFactory dynamicFactory = new DynamicFactory();

    /**
     * groovy类加载器
     */
    private GroovyClassLoader groovyClassLoader = new GroovyClassLoader();

    /**
     * 缓存Class
     */
    private ConcurrentHashMap<String, Class<?>> classCache = new ConcurrentHashMap<>();

    /**
     * 获取单例
     *
     * @return 实例
     */
    public static DynamicFactory getInstance() {
        return dynamicFactory;
    }


    /**
     * 加载创建实例，prototype
     *
     * @param codeSource 源代码
     * @return 实例
     * @throws Exception 异常
     */
    public IScript loadNewInstance(String codeSource) throws Exception {
        if (StrUtil.isNotBlank(codeSource)) {
            Class<?> aClass = getCodeSourceClass(codeSource);
            if (aClass != null) {
                Object instance = aClass.newInstance();
                if (instance != null) {
                    if (instance instanceof IScript) {
                        this.inject((IScript) instance);
                        return (IScript) instance;
                    } else {
                        throw new IllegalArgumentException(StrUtil.format("创建实例失败，[{}]不是IScript的子类", instance.getClass()));
                    }
                }
            }
        }
        throw new IllegalArgumentException("创建实例失败，instance is null");
    }

    /**
     * code text -> class
     * 通过类加载器生成class
     *
     * @param codeSource 源代码
     * @return class
     */
    private Class<?> getCodeSourceClass(String codeSource) {
        String md5 = SecureUtil.md5(codeSource);
        Class<?> aClass = classCache.get(md5);
        if (aClass == null) {
            aClass = groovyClassLoader.parseClass(codeSource);
            classCache.putIfAbsent(md5, aClass);
        }
        return aClass;
    }


    /**
     * 对script对象处理
     *
     * @param script {@link IScript}
     */
    public void inject(IScript script) {
        // to do something
    }

    public static void main(String[] args) throws Exception {
        DynamicFactory dynamicFactory = DynamicFactory.getInstance();
        ScriptExecutor executor = new ScriptExecutor();
        String codeSource = "package com.groovy.demo;\n" +
                "\n" +
                "import org.slf4j.Logger;\n" +
                "import org.slf4j.LoggerFactory;\n" +
                "\n" +
                "/**\n" +
                " * @author donghaibin\n" +
                " * @date 2019/11/19\n" +
                " */\n" +
                "public class SimpleScript implements IScript{\n" +
                "\n" +
                "\tprivate static final Logger log = LoggerFactory.getLogger(SimpleScript.class);\n" +
                "\n" +
                "\t@Override\n" +
                "\tpublic String run(String param) {\n" +
                "\t\tlog.info(\"输入的参数是:[{}]\", param);\n" +
                "\t\tlog.info(\"你好世界\");\n" +
                "\t\treturn \"hello world\";\n" +
                "\t}\n" +
                "\n" +
                "}\n";
        IScript script = dynamicFactory.loadNewInstance(codeSource);
        String id = "1";
        executor.register(id, script);

        for (int i = 0; i < 10; i++) {
            String result = executor.run(id, "abc");
            System.out.println("结果:"+result);
        }
    }
}
